package com.mtgdeckbuilder.client.builder;

import java.io.IOException;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.KeyCodes;
import com.google.gwt.event.dom.client.KeyUpEvent;
import com.google.gwt.event.dom.client.KeyUpHandler;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.DialogBox;
import com.google.gwt.user.client.ui.HasHorizontalAlignment;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.Image;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.Panel;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.mtgdeckbuilder.client.CardService;
import com.mtgdeckbuilder.client.CardServiceAsync;
import com.mtgdeckbuilder.client.DeckService;
import com.mtgdeckbuilder.client.DeckServiceAsync;
import com.mtgdeckbuilder.shared.WizardGathererSiteUtil;
import com.mtgdeckbuilder.shared.dto.CardDTO;
import com.mtgdeckbuilder.shared.dto.DeckDTO;

/**
 * The builder of the deck panel
 * 
 * @author Nicolas Deslandes
 */
public class DeckPanelBuilder extends PanelBuilder {

   private final DeckServiceAsync deckService = GWT.create(DeckService.class);
   private final CardServiceAsync cardService = GWT.create(CardService.class);

   private static final Logger logger = Logger.getLogger("DeckPanelBuilder");

   @Override
   public Panel build() {
      final VerticalPanel deckPanel = new VerticalPanel();
      final VerticalPanel resultTable = new VerticalPanel();
      final HorizontalPanel searchPanel = new HorizontalPanel();
      deckPanel.add(searchPanel);
      final TextBox searchField = new TextBox();
      searchField.addStyleName("searchField");
      searchPanel.add(searchField);
      final Button searchButton = new Button("Search");
      searchButton.addStyleName("button");
      searchPanel.add(searchButton);

      final DialogBox createBox = buildCreateBox();
      createBox.hide();

      final Button createButton = new Button("Create");
      createButton.addStyleName("button");
      createButton.addClickHandler(new ClickHandler() {

         @Override
         public void onClick(final ClickEvent event) {
            createBox.show();

         }
      });
      searchPanel.add(createButton);
      deckPanel.add(resultTable);
      resultTable.setWidth("100%");
      resultTable.setBorderWidth(1);
      resultTable.setVisible(false);

      // Focus the cursor on the name field when the app loads
      searchField.setFocus(true);
      searchField.selectAll();

      // Create a handler for the sendButton and nameField
      class SearchHandler implements ClickHandler, KeyUpHandler {
         /**
          * Fired when the user clicks on the sendButton.
          */
         @Override
         public void onClick(final ClickEvent event) {
            sendNameToServer();
         }

         /**
          * Fired when the user types in the nameField.
          */
         @Override
         public void onKeyUp(final KeyUpEvent event) {
            if (event.getNativeKeyCode() == KeyCodes.KEY_ENTER) {
               sendNameToServer();
            }
         }

         /**
          * Send the name from the nameField to the server and wait for a response.
          * 
          * @throws IOException
          */
         private void sendNameToServer() {

            resultTable.clear();
            final String textToServer = searchField.getText();
            final DeckDTO args = new DeckDTO();
            args.setName(textToServer);
            // Then, we send the input to the server.
            deckService.query(args, new AsyncCallback<List<DeckDTO>>() {
               @Override
               public void onFailure(final Throwable caught) {
                  logger.log(Level.SEVERE, "Exception with deckService.query", caught);
               }

               @Override
               public void onSuccess(final List<DeckDTO> decks) {
                  for (final DeckDTO deck : decks) {
                     final VerticalPanel result = new VerticalPanel();
                     result.setWidth("100%");
                     final HorizontalPanel resultInfo = new HorizontalPanel();
                     resultInfo.setWidth("100%");
                     resultTable.add(result);

                     resultInfo.add(new Label(deck.getName()));
                     resultInfo.add(new Label(String.valueOf(deck.getCards().size())));
                     resultInfo.add(new Label(deck.getColor()));
                     result.add(resultInfo);
                     final VerticalPanel resultCards = new VerticalPanel();
                     resultCards.setWidth("100%");
                     result.add(resultCards);
                     for (final CardDTO card : deck.getCards()) {
                        resultCards.add(new Label(card.getName()));
                     }
                  }
                  resultTable.setVisible(true);
               }
            });
         }
      }

      // Add a handler to send the name to the server
      final SearchHandler handler = new SearchHandler();
      searchButton.addClickHandler(handler);

      searchField.addKeyUpHandler(handler);

      return deckPanel;
   }

   private DialogBox buildCreateBox() {
      final DeckDTO deck = new DeckDTO();

      final DialogBox dialogBox = new DialogBox();
      dialogBox.setText("Create a new deck");
      dialogBox.setAnimationEnabled(true);
      final Button cancelButton = new Button("Cancel");
      final Button saveButton = new Button("Save");
      final TextBox nameField = new TextBox();
      final VerticalPanel dialogVPanel = new VerticalPanel();

      final HorizontalPanel buttonPanel = new HorizontalPanel();
      buttonPanel.setHorizontalAlignment(HasHorizontalAlignment.ALIGN_RIGHT);
      buttonPanel.add(cancelButton);
      buttonPanel.add(saveButton);

      final TextBox cardField = new TextBox();

      final HorizontalPanel namePanel = new HorizontalPanel();
      namePanel.setHorizontalAlignment(HasHorizontalAlignment.ALIGN_RIGHT);
      namePanel.add(new Label("Name : "));
      namePanel.add(nameField);
      nameField.addKeyUpHandler(new KeyUpHandler() {

         @Override
         public void onKeyUp(final KeyUpEvent event) {
            if (event.getNativeKeyCode() == KeyCodes.KEY_ENTER) {
               cardField.setFocus(true);
            }
         }
      });
      dialogVPanel.add(namePanel);

      final VerticalPanel vCardPanel = new VerticalPanel();

      dialogVPanel.add(cardField);
      dialogVPanel.add(vCardPanel);

      dialogVPanel.add(buttonPanel);
      cardField.addKeyUpHandler(new KeyUpHandler() {

         @Override
         public void onKeyUp(final KeyUpEvent event) {
            if (event.getNativeKeyCode() == KeyCodes.KEY_ENTER) {
               final String cardName = cardField.getText();
               final HorizontalPanel cardPanel = new HorizontalPanel();
               final Label cardLabel = new Label(cardName);
               cardPanel.add(cardLabel);
               vCardPanel.add(cardPanel);
               cardField.setText(null);
               cardField.setFocus(true);
               final CardDTO card = new CardDTO();
               card.setName(cardName);
               cardService.queryDatabase(card, 1, new AsyncCallback<List<CardDTO>>() {

                  @Override
                  public void onSuccess(final List<CardDTO> cards) {
                     if (!cards.isEmpty()) {
                        final CardDTO card = cards.get(0);
                        cardLabel.setText(card.getName());
                        cardLabel.addStyleName("clickable");
                        cardLabel.addClickHandler(new ClickHandler() {

                           @Override
                           public void onClick(final ClickEvent event) {
                              showImageBox(card.getMultiverseId());
                           }
                        });

                        final HorizontalPanel costPanel = new HorizontalPanel();
                        for (final String cost : card.getCost().split("*")) {
                           final Image costImage = new Image(WizardGathererSiteUtil.getSmallSymbolUrl + cost);
                           costPanel.add(costImage);
                        }
                        // final Label costLabel = new Label(card.getCost());
                        // costLabel.setHorizontalAlignment(HasHorizontalAlignment.ALIGN_RIGHT);
                        // costLabel.setWidth("100%");
                        // cardPanel.add(costLabel);
                        cardPanel.add(costPanel);
                        deck.getCards().add(card);
                     } else {
                        final Button getInfoButton = new Button("Get information");
                        cardPanel.add(getInfoButton);
                        getInfoButton.addClickHandler(new ClickHandler() {

                           @Override
                           public void onClick(final ClickEvent event) {
                              cardService.queryMagicSource(card, 1, new AsyncCallback<List<CardDTO>>() {

                                 @Override
                                 public void onSuccess(final List<CardDTO> cards) {
                                    final CardDTO card = cards.get(0);
                                    cardLabel.setText(card.getName());
                                    cardLabel.addClickHandler(new ClickHandler() {

                                       @Override
                                       public void onClick(final ClickEvent event) {
                                          showImageBox(card.getMultiverseId());
                                       }
                                    });

                                    final HorizontalPanel costPanel = new HorizontalPanel();
                                    for (final String cost : card.getCost().split("*")) {
                                       final Image costImage = new Image(WizardGathererSiteUtil.getSmallSymbolUrl + cost);
                                       costPanel.add(costImage);
                                    }
                                    // final Label costLabel = new Label(card.getCost());
                                    // costLabel.setHorizontalAlignment(HasHorizontalAlignment.ALIGN_RIGHT);
                                    // costLabel.setWidth("100%");
                                    // cardPanel.add(costLabel);
                                    cardPanel.add(costPanel);
                                    deck.getCards().add(card);
                                    cardPanel.remove(getInfoButton);
                                 }

                                 @Override
                                 public void onFailure(final Throwable caught) {
                                    logger.log(Level.SEVERE, "Exception with cardService.queryMagicSource", caught);
                                 }

                              });
                           }
                        });
                     }
                  }

                  @Override
                  public void onFailure(final Throwable caught) {
                     logger.log(Level.SEVERE, "Exception with cardService.queryDatabase", caught);
                  }
               });
            }
         }
      });

      saveButton.addClickHandler(new ClickHandler() {
         @Override
         public void onClick(final ClickEvent event) {
            deck.setName(nameField.getText());
            deckService.save(deck, new AsyncCallback<Void>() {

               @Override
               public void onSuccess(final Void result) {
                  dialogBox.hide();
                  vCardPanel.clear();
                  cardField.setText(null);
                  nameField.setText(null);
                  deck.reset();
               }

               @Override
               public void onFailure(final Throwable caught) {
                  logger.log(Level.SEVERE, "Exception with deckService.save", caught);
               }
            });
         }
      });

      cancelButton.addClickHandler(new ClickHandler() {
         @Override
         public void onClick(final ClickEvent event) {
            dialogBox.hide();
            vCardPanel.clear();
            cardField.setText(null);
            nameField.setText(null);
            deck.reset();
         }
      });

      dialogBox.setWidget(dialogVPanel);
      dialogBox.center();

      return dialogBox;
   }

   private void showImageBox(final Long multiverseId) {
      final VerticalPanel panel = new VerticalPanel();
      final String url = WizardGathererSiteUtil.getImageUrl + multiverseId;
      final DialogBox imageBox = new DialogBox();
      final Image image = new Image(url);
      panel.add(image);
      imageBox.add(panel);
      final Button closeButton = new Button("Close");
      closeButton.addStyleName("button");
      panel.add(closeButton);
      imageBox.show();

      closeButton.addClickHandler(new ClickHandler() {
         @Override
         public void onClick(final ClickEvent event) {
            imageBox.hide();
         }
      });
   }

}
